﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace CharmL {
    public class Dbase_Ctrl_Blk {
        private FileStream fd { get; set; }
        public StreamReader reader { get; set; }
        //        private:

        //  //vars related to the horizontal format
        //   ifstream fd;
        //   int buf_size;
        //   int * buf;
        //   int cur_blk_size; 
        //   int cur_buf_pos;
        //   int endpos;
        //   char readall;   
        //   static int *PvtTransAry;
        private int buf_size { get; set; }

        private List<int> buf { get; set; }
        private int cur_blk_size { get; set; }
        private int cur_buf_pos { get; set; }
        private long endpos { get; set; }
        private char readall { get; set; }
        private static List<int> PvtTransAry { get; set; }
        //public:
        //   static int NumF1;   //number of freq items
        //   static int *FreqMap; //mapping of freq items, i.e., item to freq_idx
        public int NumF1 { get; set; }
        public List<int> FreqMap { get; set; }
        //   static int *FreqIdx; //freq_idx to original item value
        public List<int> FreqIdx { get; set; }
        public static bool binary_input { get; set; }
        public static bool nooffset { get; set; } //read a DB not in IBM format, just itemsets
        //   //vars related to the horizontal format
        //public static int* TransAry { get; set; }
        public List<int> TransAry { get; set; }
        public int TransSz { get; set; }
        public int Tid { get; set; }
        public int Cid { get; set; }
        public int MaxTransSz { get; set; }
        public int Cidsum { get; set; } //used for closed sets
        public string FileName { get; set; }
        //   //vars related to vertical format
        //   static vector<Eqnode *> ParentClass;
        public List<Eqnode> ParentClass { get; set; }
        //   static int *class_sz;
        //   static int *F2sum;
        public static List<int> class_sz { get; set; }
        public static List<int> F2sum { get; set; }

        static Dbase_Ctrl_Blk() {
            nooffset = true;
        }
        public Dbase_Ctrl_Blk() {
            FreqIdx = null;
            FreqMap = null;
            MaxTransSz = 0;
            TransSz = 0;
            TransAry = null;
            Tid = 0;
            Cid = 0;
            NumF1 = 0;
            Cidsum = 0;
            PvtTransAry = null;
            class_sz = null;
            F2sum = null;
            //vector<Eqnode *> Dbase_Ctrl_Blk::ParentClass;
            binary_input = false;
            FreqIdx = new List<int>();
        }

        public Dbase_Ctrl_Blk(string fileName, int buf_sz = 20000) {

            //            Dbase_Ctrl_Blk::Dbase_Ctrl_Blk(const char *infile, const int buf_sz)
            //{
            //   if (binary_input){
            //      fd.open(infile, ios::binary);
            //      if (!fd.is_open()){
            //         cerr << "cannot open infile" << infile << endl;
            //         exit(1);
            //      }
            //   }
            //   else{
            //      fd.open(infile);
            //      if (!fd.is_open()){
            //         cerr << "cannot open infile" << infile << endl;
            //         exit(1);
            //      }
            //   }   
            FileName = fileName;
            if (binary_input) {
                //TODO

            } else {
            }
            //fd = new StreamReader(fileName);
            //fd = new FileStream(fileName, FileMode.Open);
            reader = new StreamReader(fileName);

            //modified
            //buf_size = buf_sz;
            //buf = new List<int>(buf_sz);
            //cur_buf_pos = 0;
            //cur_blk_size = 0;
            //readall = '0';
            //endpos = fd.Length;
            //if (nooffset) {
            //    Tid = Cid = -1;
            //}
            //end of modified

            //        buf_size = buf_sz;
            //buf = new int [buf_sz];
            //cur_buf_pos = 0;
            //cur_blk_size = 0;
            //readall = 0;
            //fd.seekg(0,ios::end);
            //endpos = fd.tellg();
            //fd.seekg(0,ios::beg);

            //if (nooffset){
            //   Tid = Cid = -1;
            //}
        }

        

        public void reset() {
            //readall = '0';
            //fd.Seek(0, SeekOrigin.Begin);
            //cur_buf_pos = 0;
            //if (nooffset) {
            //    Tid = Cid = 0;
            //}
            //readall = 0;
            //fd.clear();
            //fd.seekg(0,ios::beg);
            reader = new StreamReader(FileName);
            if (nooffset) {
                Cid = Tid = 0;
            }
            //cur_buf_pos = 0;
            //if (nooffset){
            //   Tid = Cid = 0;
            //}
        }

        public void GetFirstBlk() {

            //        void Dbase_Ctrl_Blk::get_first_blk()
            //{
            //   reset();
            //   if (binary_input){
            //      fd.read((char *)buf, (buf_size*ITSZ));
            //      cur_blk_size = fd.gcount()/ITSZ; 
            //      if (cur_blk_size < 0){
            //         cerr << "problem in get_first_blk" << cur_blk_size << endl;
            //      }
            //      if (cur_blk_size < buf_size){
            //         fd.clear();
            //         fd.seekg(0,ios::end);
            //      }
            //   }
            //}
        }


        public bool GetNextTrans() {
            //            int Dbase_Ctrl_Blk::get_next_trans ()
            //{
            //   static char first=1;  
            //   static const int linesz = 16834;
            //   static const int wordsz = 1024;
            //   static char line[linesz];
            //   static char word[wordsz];

            //   if (binary_input){
            //      if (first){
            //         first = 0;
            //         get_first_blk();
            //      }

            //      if (cur_buf_pos+TRANSOFF >= cur_blk_size ||
            //          cur_buf_pos+buf[cur_buf_pos+TRANSOFF-1]+TRANSOFF > cur_blk_size){
            //         //fd.seekg(0,ios::cur);
            //         //if ((int)fd.tellg() == endpos) readall = 1;      
            //         if (fd.eof()) readall = 1;
            //         if (!readall){
            //            // Need to get more items from file
            //            get_next_trans_ext();
            //         }      
            //      }

            //      if (eof()){
            //         first = 1;
            //         return 0;
            //      }                     

            //      if (!readall){
            //         Cid = buf[cur_buf_pos];
            //         Tid = buf[cur_buf_pos+TRANSOFF-2];
            //         TransSz = buf[cur_buf_pos+TRANSOFF-1];
            //         TransAry = buf + cur_buf_pos + TRANSOFF;
            //         cur_buf_pos += TransSz + TRANSOFF;
            //      }
            //      return 1;
            //   }
            //   else{
            //      //fd.seekg(0,ios::cur);
            //      //if (fd.tellg() == endpos) readall = 1;


            string line = reader.ReadLine();
            //      fd.getline(line, linesz);
            //      int line_len = fd.gcount();//how many chars read
            //      if (fd.eof()){
            //         first = 0;
            //         reset();
            //         return 0;
            //      }
            //      else{            
            if (string.IsNullOrEmpty(line)) {

                reset();
                return false;
            }
            char[] delimiters = new char[] { ' ' };
            string[] parts = line.Split(delimiters, StringSplitOptions.RemoveEmptyEntries);
            if (parts == null || parts.Length == 0) return false;

            int index = 0;
            if (nooffset) {
                Cid++;
                Tid++;
                TransSz = 0;
            } else {


                Cid = int.Parse(parts[0]);
                Tid = int.Parse(parts[1]);
                TransSz = int.Parse(parts[2]);
                index = 3;
                TransSz = 3;

            }
            TransAry = new List<int>();
            for (int i = index; i < parts.Length; i++) {

                TransAry.Add(int.Parse(parts[i]));
            }
            TransSz += parts.Length;
            return true;

            //         //istringstream istrs ((char *)line.c_str());
            //         parseline pl(line, line_len);
            //         //cout << "LINE " << line.c_str() << endl;
            //         if (nooffset){
            //            Cid++;
            //            Tid++;
            //         }
            //         else{
            //            pl.next(word);
            //            Cid = atoi(word);
            //            pl.next(word);
            //            Tid = atoi(word);
            //            pl.next(word);
            //            TransSz = atoi(word);
            //            //cout << " CAME HERE\n";
            //         }

            //         //cout << "CID " << Cid << " " << Tid << " " << TransSz << endl;
            //         TransSz = 0;
            //         while (pl.next(word)){
            //            buf[TransSz] = atoi(word);
            //            TransSz++;
            //         }

            //         TransAry = buf;
            //         cur_buf_pos = 0;

            //         //cout << "ENDPOS " << fd.tellg() << " " << endpos << endl;

            //         return 1;
            //      }
            //   }
            //}

        }
        //   //function definitions
        //   Dbase_Ctrl_Blk(const char *infile, const int buf_sz=DCBBUFSZ);
        //   ~Dbase_Ctrl_Blk();

        //   //functions for horizontal format
        //   void get_next_trans_ext();
        //   void get_first_blk();
        //   void reset();
        //   int get_next_trans();
        //   void get_valid_trans();
        //   void print_trans();
        //   int eof(){return (readall == 1);}

        //   //functions for vertical format
        //   void make_vertical();
        //   void print_vertical();
        //   void alloc_ParentClass(vector<int> &itcnt);
        //   void sort_ParentClass();
        //   static bool incr_cmp(Eqnode *n1, Eqnode *n2);
        //   static bool decr_cmp(Eqnode *n1, Eqnode *n2);

        internal void AllocParentClass(List<int> itcnt) {
            ParentClass = new List<Eqnode>(NumF1);
            for (int i = 0; i < NumF1; ++i) {
                ParentClass.Add(new Eqnode(i, itcnt[FreqIdx[i]]));
                if (Paramenters.diff_type == diff_vals.diffin) ParentClass[i].Hval = Cidsum;
            }
            //void Dbase_Ctrl_Blk::alloc_ParentClass(vector<int> &itcnt)
            //{
            //   //allocate space for Idlists
            //   ParentClass.resize(NumF1);
            //   for (int i=0; i < NumF1; ++i){
            //      ParentClass[i] = new Eqnode(i, itcnt[FreqIdx[i]]);   
            //      if (diff_type == diffin) ParentClass[i]->hval = Cidsum;
            //   }
            //}
        }

        internal void GetValidTrans() {
            //throw new NotImplementedException();
            //            void Dbase_Ctrl_Blk::get_valid_trans()
            //{
            //   int i,j;
            //   const int invalid=-1; //-1 does not appear in original trans
            int i, j;
            const int invalid = -1; //-1 does not appear in original trans
            //   if (PvtTransAry == NULL)
            //      PvtTransAry = new int [MaxTransSz];
            //if (PvtTransAry == null) {
            PvtTransAry = new List<int>(MaxTransSz);
            //for (int k = 0; k < MaxTransSz; k++) {
            for (int k = 0; k < TransSz; k++) {
                PvtTransAry.Add(-1);
            }
            // }

            //   //copy valid items to PvtTransAry
            //   for (i=0,j=0; i < TransSz; ++i){
            //      if (FreqMap[TransAry[i]] != invalid){
            //         PvtTransAry[j] = FreqMap[TransAry[i]];
            //         ++j;
            //      }
            //   }
            //copy valid items to PvtTransAry
            for (i = 0, j = 0; i < TransSz; ++i) {
                if (FreqMap[TransAry[i]] != invalid) {
                    PvtTransAry[j] = FreqMap[TransAry[i]];
                    //++j;
                    // PvtTransAry.Add(FreqMap[TransAry[i]]);
                    ++j;
                }
            }
            //   TransAry = PvtTransAry;
            //   TransSz = j;
            TransAry = PvtTransAry;
            TransSz = j;

            //   //cout << "NEW " << endl;
            //   //for (i=0; i < TransSz; ++i)
            //   //   cout << TransAry[i] << " ";
            //   //cout << endl;
            //}
        }

        internal void MakeVertical() {
            int i, j;

            ////convert current transaction into vertical format
            //if (diff_type == diffin) {
            //    //create a diffset
            //    for (i = 0, j = 0; i < TransSz; ++j) {
            //        if (j == TransAry[i]) {
            //            ++i;
            //        } else {
            //            ParentClass[j]->tidset.push_back(Cid);
            //            ParentClass[j]->hval -= Cid; //used for closed sets
            //        }
            //    }
            //    for (; j < NumF1; ++j) {
            //        ParentClass[j]->tidset.push_back(Cid);
            //        ParentClass[j]->hval -= Cid; //used for closed sets
            //    }
            if (Paramenters.diff_type == diff_vals.diffin) {
                for (i = 0, j = 0; i < TransSz; ++j) {
                    if (j == TransAry[i]) {
                        ++i;
                    } else {
                        ParentClass[j].TidSet.Add(Cid);
                        ParentClass[j].Hval -= Cid; //used for closed sets
                    }
                }
                for (; j < NumF1; ++j) {
                    ParentClass[j].TidSet.Add(Cid);
                    ParentClass[j].Hval -= Cid; //used for closed sets
                }
            } else {
                //create a tidset
                for (i = 0; i < TransSz; ++i) {
                    //cout << "push " << TransAry[i] << " " << Cid << endl;
                    ParentClass[TransAry[i]].TidSet.Add(Cid);
                    ParentClass[TransAry[i]].Hval += Cid; //used for closed sets
                }
            }
            //} else {
            //    //create a tidset
            //    for (i = 0; i < TransSz; ++i) {
            //        //cout << "push " << TransAry[i] << " " << Cid << endl;
            //        ParentClass[TransAry[i]]->tidset.push_back(Cid);
            //        ParentClass[TransAry[i]]->hval += Cid; //used for closed sets
            //    }
            //}
        }

        public static int incr_cmp(Eqnode n1, Eqnode n2) {
            if (class_sz[n1.Val] < class_sz[n2.Val]) return 1;
            else if (class_sz[n1.Val] == class_sz[n2.Val]) {
                if (F2sum[n1.Val] < F2sum[n2.Val]) return 1;
                else if (F2sum[n1.Val] == F2sum[n2.Val]) {
                    if (n1.Sup < n2.Sup) return 1;
                    else if (n1.Sup == n2.Sup) return 0; 
                    else return -1;
                } else return -1;
            } else return -1;
            //if (F2sum[n1->val] < F2sum[n2->val]) return true;
            //else return false;
        }

        public static int decr_cmp(Eqnode n1, Eqnode n2) {
            return incr_cmp(n1, n2) * -1;
        }

        Comparison<Eqnode> incrCmp = new Comparison<Eqnode>(incr_cmp);
        Comparison<Eqnode> decrCmp = new Comparison<Eqnode>(decr_cmp);
        internal void sort_ParentClass() {
            if (Paramenters.sort_type == sort_vals.incr) {
                ParentClass.Sort(incrCmp);
                //ParentClass.Sort(delegate(Eqnode n1, Eqnode n2) {
                //});
                // ParentClass.Sort( new IncrCmpComparer());
                //sort(ParentClass.begin(), ParentClass.end(), incr_cmp);
            } else if (Paramenters.sort_type == sort_vals.incr_noclass) {
                //sort(ParentClass.begin(), ParentClass.end(), Eqnode::incr_cmp);
                ParentClass.Sort(new IncrCmpComparer());
            } else if (Paramenters.sort_type == sort_vals.decr) {
                ParentClass.Sort(decrCmp);
                //sort(ParentClass.begin(), ParentClass.end(), decr_cmp);
            }

        }
    }
}
